import json

from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5, pkcs1_15
from apps.common.utils.tools import random_str
import base64
import datetime
from project.settings import BASE_DIR
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import random
import string
import time
import requests

def sign_str(sign_list):
    sign_list = sign_list
    return '\n'.join(sign_list) + '\n'

# 生成签名
def getSign(sign_list):
    signstr = sign_str(sign_list)
    print('signstr', signstr)
    # signstr = sign_str(method=params.get('method'), url_path=params.get('url_path'), timestamp=params.get('timestamp'), nonce_str=params.get('nonce_str'),request_body=json.dumps(body))

    apiclient_key = "{}/apps/pay/cert/apiclient_key.pem".format(BASE_DIR)
    with open(apiclient_key, 'r') as f:
        # 这里要注意的秘钥只能有三行
        # -----BEGIN PRIVATE KEY-----
        # ******************秘钥只能在一行，不能换行*****************
        # -----END PRIVATE KEY-----
        private_key = f.read()
        f.close()
        pkey = RSA.importKey(private_key)
        h = SHA256.new(signstr.encode('utf-8'))
        signature = PKCS1_v1_5.new(pkey).sign(h)
        sign = base64.b64encode(signature).decode()
        print('sign', sign)
        return sign


# 生成 Authorization
def getAuthorization(params, body=None):
    # 加密子串
    # print("加密原子串：" + signstr)
    # 加密后子串
    s = getSign([params.get('method'), params.get('url_path'), params.get('timestamp'), params.get('nonce_str'), json.dumps(body)])
    # print("加密后子串：" + s)
    authorization = 'WECHATPAY2-SHA256-RSA2048 ' \
                    'mchid="{mchid}",' \
                    'nonce_str="{nonce_str}",' \
                    'signature="{sign}",' \
                    'timestamp="{timestamp}",' \
                    'serial_no="{serial_no}"'. \
        format(
            mchid=body.get('mchid'),
            nonce_str=params.get('nonce_str'),
            sign=s,
            timestamp=params.get('timestamp'),
            serial_no=params.get('serial_no')
           )
    print('authorization', authorization)
    return authorization


def wx_decrypt(nonce, ciphertext, associated_data, pay_key):
    key_bytes = str.encode(pay_key)  # APIv3_key(商户平台设置)
    nonce_bytes = str.encode(nonce)
    ad_bytes = str.encode(associated_data)
    data = base64.b64decode(ciphertext)
    aesgcm = AESGCM(key_bytes)
    plaintext = aesgcm.decrypt(nonce_bytes, data, ad_bytes)
    plaintext_str = bytes.decode(plaintext)

    return eval(plaintext_str)

def check_wx_cert(response, mchid, pay_key, serial_no):
    """
    微信平台证书
    :param response: 请求微信支付平台所对应的的接口返回的响应值
    :param mchid: 商户号
    :param pay_key: 商户号秘钥
    :param serial_no: 证书序列号
    :return:
    """
    wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate = None, None, None, None, None
    try:
        # 11.应答签名验证
        wechatpay_serial = response.headers['Wechatpay-Serial']  # 获取HTTP头部中包括回调报文的证书序列号
        wechatpay_signature = response.headers['Wechatpay-Signature']  # 获取HTTP头部中包括回调报文的签名
        wechatpay_timestamp = response.headers['Wechatpay-Timestamp']  # 获取HTTP头部中包括回调报文的时间戳
        wechatpay_nonce = response.headers['Wechatpay-Nonce']  # 获取HTTP头部中包括回调报文的随机串
        # 11.1.获取微信平台证书 （等于又把前面的跑一遍，实际上应是获得一次证书就存起来，不用每次都重新获取一次）
        url2 = "https://api.mch.weixin.qq.com/v3/certificates"
        # 11.2.生成证书请求随机串
        random_str2 = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
        # 11.3.生成证书请求时间戳
        time_stamps2 = str(int(time.time()))
        # 11.4.生成请求证书的签名串
        data2 = ""
        sign_str2 = f"GET\n{'/v3/certificates'}\n{time_stamps2}\n{random_str2}\n{data2}\n"
        # 11.5.生成签名
        # sign2 = get_sign(sign_str2)
        sign2 = getSign(['GET', '/v3/certificates', time_stamps2, random_str2, data2])
        # 11.6.生成HTTP请求头
        headers2 = {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": 'WECHATPAY2-SHA256-RSA2048 '
                             + f'mchid="{mchid}",nonce_str="{random_str2}",signature="{sign2}",timestamp="{time_stamps2}",serial_no="{serial_no}"'
        }
        # 11.7.发送请求获得证书
        response2 = requests.get(url2, headers=headers2)  # 只需要请求头
        cert = response2.json()

        # 11.8.证书解密
        nonce = cert["data"][0]['encrypt_certificate']['nonce']
        ciphertext = cert["data"][0]['encrypt_certificate']['ciphertext']
        associated_data = cert["data"][0]['encrypt_certificate']['associated_data']
        serial_no = cert["data"][0]['serial_no']
        certificate = wx_decrypt(nonce, ciphertext, associated_data, pay_key)
    except Exception as e:
        print(f"微信平台证书验证报错：{e}")
        # log.error(f"微信平台证书验证报错：{e}；{traceback.format_exc()}")
    return wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate, serial_no


def verify(check_data, signature, certificate):
    """
    验签函数
    :param check_data:
    :param signature:
    :param certificate:
    :return:
    """
    key = RSA.importKey(certificate)  # 这里直接用了解密后的证书，但没有去导出公钥，似乎也是可以的。怎么导公钥还没搞懂。
    verifier = pkcs1_15.new(key)
    hash_obj = SHA256.new(check_data.encode('utf8'))
    return verifier.verify(hash_obj, base64.b64decode(signature))